﻿using System;
using System.Collections.Generic;
using System.ServiceModel;
using XchangeStreamer.Core.Server;
using XchangeStreamer.Core;

namespace XchangeStreamer.Server.Core
{
    internal sealed partial class Engine : ISubscriber
    {
        #region Private Fields

        private int concurrentUsers = 0;
        private System.Threading.ReaderWriterLockSlim sync;
        private Dictionary<int, List<INotification>> subscribers = new Dictionary<int, List<INotification>>();

        #endregion
        
        #region ISubscriber Members

        public void Subscribe(int topicId)
        {
            using (new UpgradeableSynchronizer(this.sync, LockType.ReaderWriterLockSlim))
            {
                List<INotification> callbacks;
                if (this.subscribers.TryGetValue(topicId, out callbacks))
                {
                    var callback = OperationContext.Current.GetCallbackChannel<INotification>();
                    if (!callbacks.Contains(callback))
                    {
                        var channel = (IContextChannel)callback;

                        channel.Faulted += new EventHandler(channel_Faulted);

                        using (new WritableSynchronizer(this.sync, LockType.ReaderWriterLockSlim))
                        {
                            callbacks.Add(callback);
                        }
                        
                        Console.WriteLine("Subscribed.");
                    }
                }
            }
        }

        public void Unsubscribe(int topicId)
        {
            using (new UpgradeableSynchronizer(this.sync, LockType.ReaderWriterLockSlim))
            {
                List<INotification> callbacks;
                if (this.subscribers.TryGetValue(topicId, out callbacks))
                {
                    if (callbacks.Count > 0)
                    {
                        var callback = OperationContext.Current.GetCallbackChannel<INotification>();
                        var channel = (IContextChannel)callback;

                        channel.Faulted -= new EventHandler(channel_Faulted);

                        using (new WritableSynchronizer(this.sync, LockType.ReaderWriterLockSlim))
                        {
                            callbacks.Remove(callback);
                        }
                        
                        Console.WriteLine("Unsubscribed.");
                    }
                }
            }
        }

        public void Connect()
        {
            System.Threading.Interlocked.Increment(ref this.concurrentUsers);
        }

        public void Disconnect()
        {
            System.Threading.Interlocked.Decrement(ref this.concurrentUsers);
        }

        #endregion

        #region Private Methods

        void channel_Faulted(object sender, EventArgs e)
        {
            Console.WriteLine("Faulted: {0}", sender.ToString());
        }

        #endregion
    }
}
